/**
 * @file uints_math.h
 * @brief 实现基于uint数组的数学运算
 * @license BSD
 */

#ifndef SM_UINTS_MATH_H
#define SM_UINTS_MATH_H

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif 

//#define UnitType uint32_t
//#define WorkType uint64_t

/**
 * 为uint数组的每一个填充相同的值
 * @param [in] v 填充数据
 */
void UInts_Fill(uint32_t *a, size_t size, uint32_t v);

/**
 * 判断a是否是由v填充，可以判断数据是否是0
 */
bool UInts_IsFilled(const uint32_t *a, size_t size, uint32_t v);

#define UInts_IsZero(a, size) UInts_IsFilled(a, size, 0)

/**
 * 拷贝a数据到b中
 * @param [in] a,size a数据及长度
 * @param [out] b b数据，其长度等于size
 */
void UInts_Copy(const uint32_t *a, size_t size, uint32_t *b);

/**
 * 将a赋值给b，长度的关系可能产生填充或截断
 * @param [in] a,asize 数据a及长度
 * @param [in,out] b,bsize 数据b及长度
 * @param [in] filling 填充数据
 * @return true表示数据无丢失，false表示数据有丢失，即截断时丢弃了非填充数据
 *
 */
bool UInts_Assign(uint32_t *a, size_t asize, const uint32_t *b, size_t bsize);

bool UInts_AssignBytes(uint32_t *a, size_t asize, const uint8_t *b, size_t bsize);

bool UInts_AssignUInt(uint32_t *a, size_t asize, uint32_t b);

bool UInts_ToBytes(const uint32_t *a, size_t asize, uint8_t *b, size_t bsize);

/**
 * 比较两个数a，b的大小
 * @return 0表示两个数相等，正数表示a>b，负数表示a<b
 */
int UInts_Compare(const uint32_t *a, size_t asize, const uint32_t *b, size_t bsize);


/**
 * 计算 c = a+b 的值，如果csize过小，则会截断
 * @return true表示没有截断，false表示有截断
 */
bool UInts_Add(const uint32_t *a, size_t asize, const uint32_t *b, size_t bsize,
			   uint32_t *c, size_t csize);


/**
 * @return true表示溢出，即a<b，false表示没有溢出
 */
bool UInts_Sub(const uint32_t *a, size_t asize, const uint32_t *b, size_t bsize, 
			   uint32_t *c, size_t csize); 


/**
 * 计算c = a*b, 要求csize = asize+bsize，避免溢出
 */
bool UInts_Mul(const uint32_t *a, size_t asize, const uint32_t *b, size_t bsize, uint32_t *c, size_t csize);



void UInts_Div(const uint32_t *a, size_t asize, const uint32_t *b, size_t bsize, 
			uint32_t *q, size_t qsize, uint32_t *r, size_t rsize);


bool UInts_LeftShift(const uint32_t *a, size_t asize, size_t bits, uint32_t *b, size_t bsize);

void UInts_Not(const uint32_t *a, uint32_t *b, size_t size);

void UInts_And(const uint32_t *a, const uint32_t *b, uint32_t *c, size_t size);
void UInts_Or(const uint32_t *a, const uint32_t *b, uint32_t *c, size_t size);
void UInts_Xor(const uint32_t *a, const uint32_t *b, uint32_t *c, size_t size);

/** bit运算对应二元扩展域的运算，与普通的运算的不同是不进位 */

/** 
 * 计算 a + b = c，等同 a ^ b = c
 * @param [in] a, asize, b, bsize
 * @param [out] c, csize
 * @return false表示c的高位有非0数据丢失
 */
bool UInts_BitAdd(const uint32_t *a, size_t asize, const uint32_t *b, size_t bsize, uint32_t *c, size_t csize);

/** 
 * 计算 a - b = c，等同 a ^ b = c
 * @param [in] a, asize, b, bsize
 * @param [out] c, csize
 * @return false表示c的高位有非0数据丢失
 */
bool UInts_BitSub(const uint32_t *a, size_t asize, const uint32_t *b, size_t bsize, uint32_t *c, size_t csize);

/** 
 * 计算 a * b = c
 * @param [in] a, asize, b, bsize
 * @param [out] c, csize
 * @return false表示c的高位有非0数据丢失
 */
bool UInts_BitMul(const uint32_t *a, size_t asize, const uint32_t *b, size_t bsize, uint32_t *c, size_t csize);

/**
 */ 
bool UInts_BitDiv(const uint32_t *a, size_t asize, const uint32_t *b, size_t bsize, uint32_t *q, size_t qsize, uint32_t *r, size_t rsize);


/**
 * 数据a的数字的个数
 * @param [in] a, asize
 * @return asize
 */
static inline size_t UInts_DigitSize(const uint32_t *a, size_t asize) { 
	return asize; 
}

/**
 * 数字非0的最高位位置
 * @param [in] a, asize
 * @return [0, UInts_DigitSize)合法位置，[UInts_DigitSize, +inf)表示数据为0
 */
size_t UInts_HighestDigit(const uint32_t *a, size_t asize);

static inline size_t UInts_GetDigit(const uint32_t *a, size_t asize, size_t index) {
	return a[asize-1-index];
}

static inline size_t UInts_DigitBitSize(const uint32_t *a, size_t asize) { 
	return 8*sizeof(uint32_t); 
}

/**
 * 数据a拥有bit的位数
 * @param [in] a, asize
 * @return asize*sizeof(uint32_t)*8
 */
static inline size_t UInts_BitSize(const uint32_t *a, size_t asize) { 
	return asize*UInts_DigitBitSize(a, asize); 
}


/**
 * bit值为true的最高位的位置
 * @param [in] a, asize
 * @return [0, UInts_BitSize)为合法位置，[UInts_BitSize, +inf)表示数据a为0 
 */
size_t UInts_HighestBit(const uint32_t *a, size_t asize);


#ifdef __cplusplus
}	// extern "C" {
#endif

#endif // SM_UINTS_MATH_H
